package com.qf.electronic.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.read.listener.ReadListener;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
//这个类就是一个模板类，使用抽象类来做的模板，这种模式就叫模板的设计模式
public abstract class AbstractExcelImporter<T> {
    //导入的时候批量处理的数量
    private final int batchProcessCount;

    private final Class<T> clazz;

    private static final BlockingQueue<Runnable> TASK_QUEUE = new LinkedBlockingQueue<>(2048);

    private static final ThreadPoolExecutor TASK_POOL = new ThreadPoolExecutor(28, 100, 1, TimeUnit.MINUTES, TASK_QUEUE);

    protected AbstractExcelImporter(Class<T> clazz, int batchProcessCount) {
        this.batchProcessCount = batchProcessCount;
        this.clazz = clazz;
    }

    //这个方法就是由用户自己去实现如何批量保存数据
    protected abstract void batchSaveData(List<T> dataList);

    /**
     * 这个方法就是导入excel的接口对接方法
     * @param in 输入流可以直接从当前请求中获取
     */
    public void importExcel(InputStream in){
        ExcelRowReadListener listener = new ExcelRowReadListener();
        ExcelReaderBuilder readerBuilder = EasyExcel.read(in, clazz, listener);
        readerBuilder.doReadAll();
        List<T> dataList = listener.getDataList();//这个方法现在获取到的就是剩余的数据，也就是不满足批处理数量还留下的数据
        //调用JDBC来完成数据的保存
//        batchSaveData(dataList);
        TASK_POOL.submit( () -> batchSaveData(dataList));
    }

    class ExcelRowReadListener implements ReadListener<T> {

        private List<T> dataList = new ArrayList<>();

        @Override
        public void invoke(T t, AnalysisContext analysisContext) {
            dataList.add(t);
            if(dataList.size() == batchProcessCount){
                //调用JDBC来完成数据的保存
                TASK_POOL.submit(new SaveTask(dataList));
                dataList = new ArrayList<>();
            }
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {

        }

        public List<T> getDataList(){
            return dataList;
        }
    }

    class SaveTask implements Runnable {

        private final List<T> dataList;

        public SaveTask(List<T> dataList) {
            this.dataList = dataList;
        }

        @Override
        public void run() {
            batchSaveData(dataList);
        }
    }
}

